// Copyright (C) 2010  Andrew H. Chan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

#ifndef _PACKED_CONFIG_H__
#define _PACKED_CONFIG_H__

#include "basic_functions.h"

class Packed_Config {
    public:
        typedef uchar data_type[NUM_HAPS];

        Packed_Config() {
            // zero-fill the data member
            for(uint ii=0; ii<NUM_HAPS; ++ii) {
                data[ii] = 0;
            }
        }
        // static members
        static int loci_defined[NUM_HAPS];
        static int breakpoints[NUM_HAPS];

        // data members
        data_type data; // uchar[NUM_HAPS]

        // functions
        size_t size() const {
            size_t tot_size = 0;
            for(uint ii=0; ii<NUM_HAPS; ++ii) {
                tot_size += static_cast<size_t>(data[ii]);
            }
            return tot_size;
        }

        void clear() {
            // zero-fill the data member
            for(uint ii=0; ii<NUM_HAPS; ++ii) {
                data[ii] = 0;
            }
        }

        size_t distinct_hap() const {
            size_t dh = 0;
            for(uint ii=0; ii<NUM_HAPS; ++ii) {
                if(data[ii] > 0)
                    ++dh;
            }
            return dh; 
        }

        size_t compute_V() const {
            size_t V = 0;
            for(uint ii=0; ii<NUM_HAPS; ++ii) {
                V += loci_defined[ii] * data[ii];
            }
            return V;
        }

        size_t compute_U() const {
            size_t U = 0;
            for(uint ii=0; ii<NUM_HAPS; ++ii) {
                U += breakpoints[ii] * data[ii];
            }
            return U;
        }

        bool empty() const {
            bool empty = true;
            for(uint ii=0; ii<NUM_HAPS; ++ii) {
                if(data[ii] > 0) {
                    empty = false;
                    break;
                }
            }
            return empty; 
        }

        bool operator==(Packed_Config const& other) const {
            bool equal = true;
            for(uint ii=0; ii<NUM_HAPS; ++ii) {
                if(data[ii] != other.data[ii]) {
                   equal = false; 
                   break;
                }
            }
            return equal; 
        }

        bool operator!=(Packed_Config const& other) const {
            return !(*this == other);
        }

        uchar& operator[](int arr_index) {
            return data[arr_index];
        }

        uchar const& operator[](int arr_index) const {
            return data[arr_index];
        }

        // max_allele parameter should be (number of alleles - 1)
        static int next_hap(index_t& index, int max_allele);

        static int compute_loci();
        static int compute_breaks();
};

// hash function for Packed_Config
size_t hash_value(Packed_Config const& packed_config);

#endif
